<?php

/** Issue # 2103 Usaepay payment interface
 *
 * 
 * This is the extended classes of the usaepay adaptor that deal with our  application actions
 */
class PgCurrency extends CurrencyObject {

}

class PgCreditCard extends CreditCardData {

}

Class PgAddress extends Address {

}

class PgPaymentMethod extends PaymentMethod {

}

class PgTransactionDetail extends TransactionDetail {

}

class PgCheckData extends CheckData {

}

class PgRecurringBilling extends RecurringBilling {

}

class PgTransactionResponse extends TransactionResponse {

}

class PgSearch extends SearchParam {

}

class PgCustomerTransactionRequest extends CustomerTransactionRequest {

}

class PgFieldValue extends FieldValue {

}

class PgLineItem extends LineItem {

}

/**
 * 
 * @uses This class contains all relevant customer data including
 * the CustNum (a unique customer number assigned by the gateway), 
 * CustID (a merchant assigned customer ID), as well as customer name, 
 * address, recurring billing status and schedule, and any other relevant data. 
 */
class PgCustomer extends CustomerObject {

    private $usepay;
    private $token;

    public function __construct($custNum=null) {
        //create instance of the token and from the webservice
        $this->usepay = new usaepayService();
        $this->token = TokenClient::getToken();

        //get customer object values in case of providing custNum
        if ($custNum) {
            $this->CustNum = $custNum;
        }
    }

    //function used to get all customer attribute from the merchant gateway
    public function loadCustomerData() {

        try {
            $cust = $this->usepay->getCustomer($this->token, $this->CustNum);
            $this->Amount = $cust->Amount;
            $this->BillingAddress = $cust->BillingAddress;
            $this->Created = $cust->Created;
            $this->Currency = $cust->Currency;

            $this->CustomData = $cust->CustomData;
            $this->CustomFields = $cust->CustomFields;
            $this->CustomerID = $cust->CustomerID;
            $this->Description = $cust->Description;
            $this->Enabled = $cust->Enabled;
            $this->Failures = $cust->Failures;
            $this->Modified = $cust->Modified;
            $this->Next = $cust->Next;
            $this->Notes = $cust->Notes;
            $this->Next = $cust->Next;
            $this->NumLeft = $cust->NumLeft;
            $this->OrderID = $cust->OrderID;
            $this->PaymentMethods = $cust->PaymentMethods;
            $this->ReceiptNote = $cust->ReceiptNote;
            $this->User = $cust->User;
            $this->URL = $cust->URL;
            $this->Tax = $cust->Tax;
            $this->Source = $cust->Source;
            $this->SendReceipt = $cust->SendReceipt;
            $this->Schedule = $cust->Schedule;
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
    }

    /*
     * The customer will be assigned a unique customer number by the gateway
     *  (CustNum), which you can then use to establish recurring billing cycles,
     *  recall customer data, and manually charge the customer for later products 
     * or services without needing to reenter their information. 
     */

    public function addCustomer($cust) {

        $usepay = $this->usepay;
        $token = $this->token;

        try {

            $this->CustNum = $usepay->addCustomer($token, $cust);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }

        $cust->CustNum = $this->CustNum;
        return $this->CustNum;
        
    }

    /*
     * This method allows you to view all of the stored data for a particular customer.
     * This method requires the use of the CustNum,
     *  a unique customer number assigned by the gateway. 
     * If you have lost or cannot remember the customer's CustNum, 
     * use the searchCustomers method to find the correct CustNum. 
     */

    public static function getCustomer($id) {
        $usepay = new usaepayService();
        $token = TokenClient::getToken();


        try {

            $Customer = $usepay->getCustomer($token, $id);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }


        return $Customer;
    }

    /*
     * This method allows you to begin a recurring billing cycle 
     * for an individual customer using their CustNum 
     * (unique customer number assigned by the gateway) 
     * as a reference. If you have lost or cannot remember 
     * the customer's CustNum, use the searchCustomerID method to retrieve it. 
     */

    public function enableCustomer() {
        try {
            $results = $this->usepay->enableCustomer($this->token, $this->CustNum);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method allows you to stop a customer's recurring billing cycle 
     * using the CustNum (unique customer number assigned by the gateway) 
     * as a reference. If you have lost or cannot remember 
     * the customer's CustNum, use the searchCustomerID method to retrieve it. 
     */

    public function disableCustomer() {
        try {
            $results = $this->usepay->disableCustomer($this->token, $this->CustNum);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Delete the customer.
     */

    public function deleteCustomer() {
        try {
            $results = $this->usepay->deleteCustomer($this->token, $this->CustNum);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method allows you to add a new payment method to a customer record. 
     */

    public function addCustomerPaymentMethod($PaymentMethod, $makeDefult, $verify) {
        try {
            $results = $this->usepay->addCustomerPaymentMethod($this->token, $this->CustNum, $PaymentMethod, $makeDefult, $verify);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Retrieve a specific customer payment method
     */

    public function getCustomerPaymentMethod($PaymentMethodID) {
        try {
            $results = $this->usepay->getCustomerPaymentMethod($this->token, $this->CustNum, $PaymentMethodID);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Retrieve the customer payment methods
     */

    public function getCustomerPaymentMethods() {
        try {
            $results = $this->usepay->getCustomerPaymentMethods($this->token, $this->CustNum);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Delete a payment method from an existing customer. 
     */

    public function deleteCustomerPaymentMethod($PaymentMethodID) {
        try {
            $results = $this->usepay->deleteCustomerPaymentMethod($this->token, $this->CustNum, $PaymentMethodID);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Replace all data for customer
     */

    public function updateCustomer() {
        try {
            $results = $this->usepay->updateCustomer($this->token, $this->CustNum, $this);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Update customer data in selected fields only. 
     */

    public function quickUpdateCustomer($fields) {
        try {
            $results = $this->usepay->quickUpdateCustomer($this->token, $this->CustNum, $fields);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Run a transaction using payment data stored in the customer database.
     */

    public function runCustomerTransaction($paymetMethodID, PgCustomerTransactionRequest $PgCustomerTransactionRequest) {
        try {
            $results = $this->usepay->runCustomerTransaction($this->token, $this->CustNum, $paymetMethodID, $PgCustomerTransactionRequest);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

}

/*
 * This class contains the data needed to run a new transaction, including sale, credit, void and authonly. 
 */

class PgTransactionRequest extends TransactionRequestObject {

    private $usepay;
    private $token;

    public function __construct() {
        $this->usepay = new usaepayService();
        $this->token = TokenClient::getToken();
    }

    /*
     * This method duplicates the functionality of the gateway API.
     *  It can be used to run a wide variety of transaction types 
     * including sales, credits, authonly, void, and checks. 
     */

    public function runTransaction() {
        try {
            $results = $this->usepay->runTransaction($this->token, $this);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method is equivalent to running the runTransaction method with the Command set to “Sale.” 
     */

    public function runSale() {
        try {
            $results = $this->usepay->runSale($this->token, $this);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method is equivalent to running the runTransaction method with the Command set to “AuthOnly.” 
     * @return TransactionResponse
     */

    public function runAuthOnly() {
        try {
            $results = $this->usepay->runAuthOnly($this->token, $this);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method refunds a sale. 
     * Both credit card and check sale transactions may be refunded.
     *  You may choose to refund the entire amount or just a portion of the original sale. 
     */

    public function refundTransaction($refNum, $amount) {
        try {
            $results = $this->usepay->refundTransaction($this->token, $refNum, $amount);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * Move an authorized transaction into the current batch for settlement.
     *  It is possible to capture an amount other than the one originally authorized,
     *  however, you must follow the guidelines established by the merchant service bank. 
     * Capturing a higher or lower dollar amount could result in additional penalties and fees. 
     */

    public function captureTransaction($refNum, $amount) {
        try {
            $results = $this->usepay->captureTransaction($this->token, $refNum, $amount);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method runs a Credit transaction in order to refund all
     *  or part of a previous Sale, or issue an open credit to a customer's credit card. 
     */

    public function runCredit() {
        try {
            $results = $this->usepay->runCredit($this->token, $this);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }


    public function getTransactionStatus($refNum){
        try {
            $results = $this->usepay->getTransactionStatus($this->token,$refNum);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

}

/**
 *  this class help to handle Batches
 */
class PgBatch {

    private $usepay;
    private $token;

    public function __construct() {
        $this->usepay = new usaepayService();
        $this->token = TokenClient::getToken();
    }

    /*
     * Use this method to search batches that you have already settled.
     *  This method allows the following fields to be used in the search:
     *
     *  abdelmohsen add the default values for the search function 
     */

    public function searchBatches($Search, $MatchAll = true, $Start = 0, $Limit = 1, $Sort = 'closed') {
        try {
            $results = $this->usepay->searchBatches($this->token, $Search, $MatchAll, $Start, $Limit, $Sort);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /**
     * This method will check on the status of any batch within the merchant console.
     *  Enter the BatchRefNum (a unique batch reference number assigned by the gateway) 
     * into the search field and the method will return the status of the requested batch.
     */
    public function getBatchStatus($batchRefNum = 0) {


        try {
            $results = $this->usepay->getBatchStatus($this->token, $batchRefNum);
        } catch (Exception $exc) {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /*
     * This method will close or settle an open batch.
     *  Upon settlement the funds will be transferred to the merchant's bank account. 
     */

    public function closeBatch($batchRefNum) {

        try {
            $results = $this->usepay->closeBatch($this->token, $batchRefNum);
        } catch (Exception $exc) {

            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }
    
    /**
     * Retrieve transactions in the batch specified by BatchRefNum
     * @param string $batchRefNum
     * @return array of TransactionObjects
     * @throws Exception 
     */
    public function getBatchTransactions($batchRefNum)
    {
        try
        {
            $results = $this->usepay->getBatchTransactions($this->token, $batchRefNum);
        } 
        catch (Exception $exc)
        {
            throw new Exception(usaepayErrorHandlee::getError($exc->getMessage()));
        }
        return $results;
    }

    /**
     * close current batch if it is opend
     *
     * @return array 
     * array[0]:    true if he can close this batch
     *              false if there is no opened batchs
     * rest of the array elements are the batchRefNum of the batch
     */
    public function closeCurrentBatch() {
        $return = array(false);

        //get the first batch according th the closed statues
        $searchArr = array(array('Field' => 'opened', 'Type' => 'gt', 'Value' => '2004-5-4'),);
        $result = $this->searchBatches($searchArr);
    
        foreach ($result->Batches as $r) {
            //loop into the returned array

            //get batch ref number
            $batchRefNum = $r->BatchRefNum;
            $return[] = $batchRefNum;

            if ($r->Status == "Open") {

                // change the batch statues
                $return[0] = $this->closeBatch($batchRefNum);
//                break;
            }
        }

        return $return;
    }

}
